package com.vvvtimes.utils;


import com.vvvtimes.enums.PluginVersionCodeEnum;
import com.vvvtimes.enums.PluginVersionEnum;
import javassist.*;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class CrackClass {

    public static void crack(String oldJarPath, String outClassPath,String version) throws NotFoundException, CannotCompileException, IOException {
    
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(oldJarPath);
        try {
			PluginVersionEnum versionEnum = PluginVersionEnum.fromCode(version);
			String className = versionEnum.getClassName();
			String methodName = versionEnum.getMethodName();
			//2023.1.3.2 类名 io.github.kings1990.plugin.fastrequest.cofig.l11Il1III1111 方法名 l111I1llllI
			//2023.1.7.1 类名 io.github.kings1990.plugin.fastrequest.cofig.I1III1lI1lI11I11 方法名 IIl1lIl1111IlIlI1
			//2023.2.1.3 类名 io.github.kings1990.plugin.fastrequest.cofig.I1lIl1lI1l1I1IlIIll 方法名 IIl1lIl1111IlIlI1
			//上层 io.github.kings1990.plugin.fastrequest.cofigll1lIlIlIIl1I1ll11I1.ll1lIlIlIIl1I1ll11I1(Project var0)
			//关键字通过 "AES"+"SHA1PRNG"加密
			//相关类 com.intellij.ui.LicensingFacade
			//定义枚举 PluginVersionEnum
			//参考逻辑 https://www.52pojie.cn/thread-1776910-1-1.html

			hookReturnFalse(pool,className,methodName,outClassPath);
			PluginVersionCodeEnum pluginVersionCodeEnum = PluginVersionCodeEnum.fromCode(version);
			if(!pluginVersionCodeEnum.getVersion().equals("default")){
				String className1 = pluginVersionCodeEnum.getClassName();
				String methodName1 = pluginVersionCodeEnum.getMethodName();
				hookReturnEmptyString(pool,className1,methodName1,outClassPath);
			}
			System.out.println("反编译class修改成功");
        } catch (NotFoundException e) {
			System.out.println("反编译class异常:" + e);
        }
    }

	private static void hookReturnVoid(ClassPool pool,String className,String methodName,String outClassPath) throws NotFoundException, CannotCompileException, IOException {
		CtClass driverclass = pool.getDefault().get(className);
		CtMethod[] declaredmethods = driverclass.getDeclaredMethods();
		CtMethod hookmethod = null;
		for (CtMethod declaredmethod : declaredmethods) {
			String name = declaredmethod.getName();
			if (name.equals(methodName)) {
				hookmethod = declaredmethod;
				break;
			}
		}
		if (hookmethod != null) {
			System.out.println(hookmethod.getDeclaringClass());
			hookmethod.setBody("return ;");
		}
		driverclass.writeFile(outClassPath);
	}

	private static void hookReturnFalse(ClassPool pool,String className,String methodName,String outClassPath) throws NotFoundException, CannotCompileException, IOException {
		CtClass driverclass = pool.getDefault().get(className);
		CtMethod[] declaredmethods = driverclass.getDeclaredMethods();
		CtMethod hookmethod = null;
		for (CtMethod declaredmethod : declaredmethods) {
			String name = declaredmethod.getName();
			if (name.equals(methodName)) {
				hookmethod = declaredmethod;
				break;
			}
		}
		if (hookmethod != null) {
			System.out.println(hookmethod.getDeclaringClass());
			hookmethod.setBody("return false;");
		}
		driverclass.writeFile(outClassPath);
	}

	private static void hookReturnEmptyString(ClassPool pool,String className,String methodName,String outClassPath) throws NotFoundException, CannotCompileException, IOException {
		CtClass driverclass = pool.getDefault().get(className);
		CtMethod[] declaredmethods = driverclass.getDeclaredMethods();
		CtMethod hookmethod = null;
		for (CtMethod declaredmethod : declaredmethods) {
			String name = declaredmethod.getName();
			if (name.equals(methodName)) {
				hookmethod = declaredmethod;
				break;
			}
		}
		if (hookmethod != null) {
			System.out.println(hookmethod.getDeclaringClass());
			hookmethod.setBody("return \"\";");
		}
		driverclass.writeFile(outClassPath);
	}

	private static void hookReturnBooleanFalse(ClassPool pool,String className,String methodName,String outClassPath) throws NotFoundException, CannotCompileException, IOException {
		CtClass driverclass = pool.getDefault().get(className);
		CtMethod[] declaredmethods = driverclass.getDeclaredMethods();
		CtMethod hookmethod = null;
		for (CtMethod declaredmethod : declaredmethods) {
			String name = declaredmethod.getName();
			if (name.equals(methodName)) {
				hookmethod = declaredmethod;
				break;
			}
		}
		if (hookmethod != null) {
			System.out.println(hookmethod.getDeclaringClass());
			hookmethod.setBody("return java.lang.Boolean.FALSE;");
		}
		driverclass.writeFile(outClassPath);
	}

	private static void hookReturn(ClassPool pool, String className, List<String> trueMethodName, List<String> falseMethodName,List<String> booleanTrueMethodName,List<String> booleanFalseMethodName, String outClassPath) throws NotFoundException, CannotCompileException, IOException {
		CtClass driverclass = pool.getDefault().get(className);
		CtMethod[] declaredmethods = driverclass.getDeclaredMethods();
		if(trueMethodName != null && trueMethodName.size()>0){
			for (String methodName :trueMethodName) {
				CtMethod hookmethod = null;
				for (CtMethod declaredmethod : declaredmethods) {
					String name = declaredmethod.getName();
					if (name.equals(methodName)) {
						hookmethod = declaredmethod;
						break;
					}
				}
				if (hookmethod != null) {
					System.out.println(hookmethod.getDeclaringClass());
					hookmethod.setBody("return true;");
				}
			}
		}
		if(falseMethodName != null && falseMethodName.size()>0){
			for (String methodName :falseMethodName) {
				CtMethod hookmethod = null;
				for (CtMethod declaredmethod : declaredmethods) {
					String name = declaredmethod.getName();
					if (name.equals(methodName)) {
						hookmethod = declaredmethod;
						break;
					}
				}
				if (hookmethod != null) {
					System.out.println(hookmethod.getDeclaringClass());
					hookmethod.setBody("return false;");
				}
			}
		}

		if(booleanTrueMethodName != null && booleanTrueMethodName.size()>0){
			for (String methodName :booleanTrueMethodName) {
				CtMethod hookmethod = null;
				for (CtMethod declaredmethod : declaredmethods) {
					String name = declaredmethod.getName();
					if (name.equals(methodName)) {
						hookmethod = declaredmethod;
						break;
					}
				}
				if (hookmethod != null) {
					System.out.println(hookmethod.getDeclaringClass());
					hookmethod.setBody("return java.lang.Boolean.TRUE;");
				}
			}
		}


		if(booleanFalseMethodName != null && booleanFalseMethodName.size()>0){
			for (String methodName :booleanFalseMethodName) {
				CtMethod hookmethod = null;
				for (CtMethod declaredmethod : declaredmethods) {
					String name = declaredmethod.getName();
					if (name.equals(methodName)) {
						hookmethod = declaredmethod;
						break;
					}
				}
				if (hookmethod != null) {
					System.out.println(hookmethod.getDeclaringClass());
					hookmethod.setBody("return java.lang.Boolean.FALSE;");
				}
			}
		}




		driverclass.writeFile(outClassPath);
	}



	private static void hookReturnTrue(ClassPool pool,String className,String methodName,String outClassPath) throws NotFoundException, CannotCompileException, IOException {
		CtClass driverclass = pool.getDefault().get(className);
		CtMethod[] declaredmethods = driverclass.getDeclaredMethods();
		CtMethod hookmethod = null;
		for (CtMethod declaredmethod : declaredmethods) {
			String name = declaredmethod.getName();
			if (name.equals(methodName)) {
				hookmethod = declaredmethod;
				break;
			}
		}
		if (hookmethod != null) {
			System.out.println(hookmethod.getDeclaringClass());
			hookmethod.setBody("return true;");
		}
		driverclass.writeFile(outClassPath);
	}


}
